package com.ruoyi.web.controller.monitor;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysUserOnlineService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 在线用户监控
 *
 * @author ruoyi
 */
@Tag(name = "在线用户监控")
@RestController
@RequestMapping("/monitor/online")
@RequiredArgsConstructor
public class SysUserOnlineController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(SysUserOnlineController.class);

    private final ISysUserOnlineService userOnlineService;
    private final SaTokenDao saTokenDao;
    
    @Value("${sa-token.token-name}")
    private String tokenName;

    @Operation(summary = "在线用户列表")
    @SaCheckPermission("monitor:online:list")
    @GetMapping("/list")
    public TableDataInfo list(String ipaddr, String userName) {
        List<SysUserOnline> userOnlineList = new ArrayList<>();

        try {
            // 构建正确的key模式：tokenName:login:session:*
            String keyPattern = tokenName + ":login:session:*";
            List<String> sessionKeys = saTokenDao.searchData(keyPattern, "*", 0, -1, false);

            for (String sessionKey : sessionKeys) {
                try {
                    // 从key中提取loginId
                    String prefix = tokenName + ":login:session:";
                    String loginId = sessionKey.replace(prefix, "");

                    // 检查该用户是否仍在线
                    if (StpUtil.isLogin(loginId)) {
                        // 直接从Redis获取session数据
                        String sessionData = saTokenDao.get(sessionKey);
                        if (StringUtils.isNotEmpty(sessionData)) {
                            JSONObject sessionJson = JSON.parseObject(sessionData);
                            
                            // 从dataMap中获取login_user_key
                            JSONObject dataMap = sessionJson.getJSONObject("dataMap");
                            if (dataMap != null) {
                                Object loginUserObj = dataMap.get(Constants.LOGIN_USER_KEY);
                                LoginUser loginUser = null;

                                // 处理不同类型的loginUser对象
                                if (loginUserObj instanceof LoginUser) {
                                    loginUser = (LoginUser) loginUserObj;
                                } else if (loginUserObj instanceof JSONObject) {
                                    JSONObject jsonObject = (JSONObject) loginUserObj;
                                    loginUser = JSON.toJavaObject(jsonObject, LoginUser.class);
                                } else if (loginUserObj != null) {
                                    String jsonStr = JSON.toJSONString(loginUserObj);
                                    loginUser = JSON.parseObject(jsonStr, LoginUser.class);
                                }

                                if (loginUser != null) {
                                    // 获取terminalList，为每个终端创建在线用户记录
                                    List<JSONObject> terminalList = null;
                                    JSONArray terminalArray = sessionJson.getJSONArray("terminalList");
                                    if (terminalArray != null) {
                                        terminalList = terminalArray.toJavaList(JSONObject.class);
                                    }
                                    if (terminalList != null && !terminalList.isEmpty()) {
                                        for (JSONObject terminal : terminalList) {
                                            String tokenValue = terminal.getString("tokenValue");
                                            
                                            // 根据筛选条件过滤
                                            SysUserOnline online = null;
                                            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
                                                online = userOnlineService.selectOnlineByInfo(ipaddr, userName, loginUser);
                                            } else if (StringUtils.isNotEmpty(ipaddr)) {
                                                online = userOnlineService.selectOnlineByIpaddr(ipaddr, loginUser);
                                            } else if (StringUtils.isNotEmpty(userName)) {
                                                online = userOnlineService.selectOnlineByUserName(userName, loginUser);
                                            } else {
                                                online = userOnlineService.loginUserToUserOnline(loginUser);
                                            }

                                            if (online != null) {
                                                online.setTokenId(tokenValue);
                                                userOnlineList.add(online);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    log.warn("处理session异常: {}", e.getMessage());
                }
            }
        } catch (Exception e) {
            log.error("获取在线用户列表异常", e);
        }
        // 按登录时间降序排列
        userOnlineList = userOnlineList.stream()
                .filter(online -> online.getLoginTime() != null)
                .sorted((a, b) -> b.getLoginTime().compareTo(a.getLoginTime()))
                .collect(Collectors.toList());
        return getDataTable(userOnlineList);
    }


    /**
     * 强退用户
     */
    @Operation(summary = "强退用户")
    @SaCheckPermission("monitor:online:forceLogout")
    @Log(title = "在线用户", businessType = BusinessType.FORCE)
    @DeleteMapping("/{tokenId}")
    public AjaxResult forceLogout(@PathVariable String tokenId) {
        try {
            // 使用SA-Token的强退API
            StpUtil.logoutByTokenValue(tokenId);
            return success("强退成功");
        } catch (Exception e) {
            log.error("强退用户失败", e);
            return error("强退失败，请检查日志");
        }
    }
}
